package com.yhy.common.feign.aspect;

import cn.hutool.json.JSONUtil;
import com.yhy.common.core.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration;

import java.util.StringJoiner;

/**
 * feign aop
 */
@Slf4j
@Aspect
@ConditionalOnMissingBean(WebFluxAutoConfiguration.class)
public class FeignExceptionAspect {

    @Pointcut("@within(org.springframework.cloud.openfeign.FeignClient)")
    public void pointcut() {
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        Boolean success = Boolean.TRUE;
        try {
            result = point.proceed();
            if (result instanceof Result && !((Result<?>) result).isSuccess()) {
                success = Boolean.FALSE;
            }
        } catch (Throwable throwable) {
            result = Result.fail(throwable.getMessage());
            success = Boolean.FALSE;
            throw throwable;
        } finally {
            printLog(point, result, success);
        }
        return result;
    }

    private void printLog(JoinPoint point, Object result, Boolean success) {
        StringJoiner logInfo = new StringJoiner("\n", "\n", "");
        String paramString = getParamStr(point);
        logInfo.add("[FEIGN-INNER:: ADDR]:  " + (point.toShortString()).replace("execution", "").replace("(..)", "").replace(")", "").replace("(", ""));
        logInfo.add("[FEIGN-INNER::PARAM]:  " + paramString);
        logInfo.add("[FEIGN-INNER:: DATA]:  " + JSONUtil.toJsonStr(result));
        if (success) {
            log.debug(logInfo.toString());
        } else {
            log.error(logInfo.toString());
        }
    }

    private String getParamStr(JoinPoint point) {
        String paramString = "[]";
        Object[] args = point.getArgs();
        if (args != null && args.length > 0) {
            paramString = JSONUtil.toJsonStr(args);
        }
        return paramString;
    }
}
